package com.calcgpa.core;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;

import com.calcgpa.core.vo.Score;
import com.calcgpa.core.vo.User;
import com.calcgpa.util.CalcGPAMethod;

public class CalcGPA {
	public final static int REQUEST_ERROR = 1;
	public final static int LOGIN_ERROR = 2;
	public final static int SUCCESS = 3;
	
	private HttpClient httpClient = new DefaultHttpClient();
	
	/**
	 * The default calc method to calculate GPA. Use template pattern.
	 * @param username
	 * @param password
	 * @param term
	 * @param isPE
	 * @return
	 */
	public int doCalc(String username, String password, String term, boolean isPE){
		init();
		if (doLogin(username, password) == LOGIN_ERROR) return LOGIN_ERROR;
		String response = doGetScores(1, term);
		if (response.indexOf("学生各类信息查询") != -1) return LOGIN_ERROR;
		List<Score> scores = analysisScore(response);
		
    	System.out.println("----------------------------------------");
    	System.out.println("Your grades in " + term + " term show as below:");
		for (Score score:scores){
			System.out.printf("%s %s %s %.3f %s %.3f\n", score.getTerm(), score.getCourse(), score.getType(),
					score.getScore(), score.getTime(), score.getCredit());
		}
		CalcGPAMethod calc = new CalcGPAMethod();
		System.out.printf("%.3f\n",calc.doCalc(scores, isPE));
		end();
		return SUCCESS;
	}
	
	protected void init(){
		if (httpClient == null) httpClient = new DefaultHttpClient();
	}
	
	protected int doLogin(String username, String password){
		try {
			String response = HttpRequest.doGet(httpClient, "http://www.ycjw.zjut.edu.cn/logon.aspx", "");
			String viewstate = getViewstate(response);
			//System.out.println(viewstate);
	        List <NameValuePair> nvps = new ArrayList <NameValuePair>();
	        nvps.add(new BasicNameValuePair("__VIEWSTATE", viewstate));
	        nvps.add(new BasicNameValuePair("Cbo_LX", "学生"));
	        nvps.add(new BasicNameValuePair("Txt_UserName", username));
	        nvps.add(new BasicNameValuePair("Txt_Password", password));
	        nvps.add(new BasicNameValuePair("Img_DL.x", "29"));
	        nvps.add(new BasicNameValuePair("Img_DL.y", "13"));
			HttpRequest.doPostWithNoResponse(httpClient, "http://www.ycjw.zjut.edu.cn/logon.aspx", nvps);
			
			HttpRequest.doGet(httpClient, "http://www.ycjw.zjut.edu.cn/stdgl/cxxt/cjcx/Cjcx_Xsgrcj.aspx", "");
		} catch (ClientProtocolException e) {
			System.out.println("登录失败");
			e.printStackTrace();
			return LOGIN_ERROR;
		} catch (IOException e) {
			System.out.println("登录失败");
			e.printStackTrace();
			return LOGIN_ERROR;
		}
		return SUCCESS;
	}
	
	protected String doGetScores(int type, String xq){
		try {
			List <NameValuePair> nvps = new ArrayList <NameValuePair>();
			nvps = new ArrayList <NameValuePair>();
			
			String response = HttpRequest.doGet(httpClient, "http://www.ycjw.zjut.edu.cn/stdgl/cxxt/cjcx/Cjcx_Xsgrcj.aspx", "");
			String viewstate = getViewstate(response);
			
	        nvps = new ArrayList <NameValuePair>();
	        nvps.add(new BasicNameValuePair("__VIEWSTATE", viewstate));
	        nvps.add(new BasicNameValuePair("__EVENTARGUMENT", null));
	        nvps.add(new BasicNameValuePair("__EVENTTARGET", null));
	        if (xq.indexOf("(") == -1){
	        	nvps.add(new BasicNameValuePair("1", "rbtnXn"));
	        	nvps.add(new BasicNameValuePair("ddlXn", xq));
	        } else {
		        nvps.add(new BasicNameValuePair("1", "rbtnXq"));
		        nvps.add(new BasicNameValuePair("ddlXq", xq));
	        }
	        nvps.add(new BasicNameValuePair("ddlKc", "＝所有课程＝"));
	        nvps.add(new BasicNameValuePair("Button1", "普通考试成绩查询"));
	       
	        String result = null;
			result = HttpRequest.doPost(httpClient, "http://www.ycjw.zjut.edu.cn//stdgl/cxxt/cjcx/Cjcx_Xsgrcj.aspx", nvps);
			return result;
		} catch (ClientProtocolException e) {
			System.out.println("成绩获取失败");
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			System.out.println("成绩获取失败");
			e.printStackTrace();
			return null;
		}
	}
	
	protected List<Score> analysisScore(String response){
        HtmlCleaner cleaner = new HtmlCleaner();
        TagNode node = cleaner.clean(response);
        Object[] nodes = new Object[0];
        List<Score> scores = new ArrayList<Score>();
		try {
			nodes = node.evaluateXPath("//table[@id='DataGrid1']//tr");
			int count = 0;
	        for (Object n1 : nodes){
	        	if (count == 0) { count++; continue;}
	        	Object[] tds = ((TagNode) n1 ).evaluateXPath("//td");
	        	String term = ((TagNode) tds[0]).getText().toString().trim();
	        	String course = ((TagNode) tds[1]).getText().toString().trim();
	        	String type = ((TagNode) tds[2]).getText().toString().trim();
	        	String scorev = ((TagNode) tds[3]).getText().toString().trim();
	        	String time = ((TagNode) tds[4]).getText().toString().trim();
	        	String credit = ((TagNode) tds[5]).getText().toString().trim();
	        	if (time.equals("&nbsp;")) time = "0";
	        	if (credit.equals("&nbsp;")) credit = "0";
	        	Score score = new Score(term, course, type, getScoreByGrade(scorev.replaceAll("&nbsp;", "")), time
	        			, Double.valueOf(credit));
	        	scores.add(score);
	        }
		} catch (XPatherException e) {
			System.out.println("成绩解析失败");
		}

		return scores;
	}
	
	protected User analysisUser(String response){
        HtmlCleaner cleaner = new HtmlCleaner();
        TagNode node = cleaner.clean(response);
        Object[] nodes = new Object[0];
        User user = new User();
		try {
			nodes = node.evaluateXPath("//span[@id='lblXh']");
			user.setId(((TagNode)nodes[0]).getText().toString().trim());
			nodes = node.evaluateXPath("//span[@id='lblXm']");
			user.setName(((TagNode)nodes[0]).getText().toString().trim());
			nodes = node.evaluateXPath("//span[@id='lblBjmc']");
			user.setClasses(((TagNode)nodes[0]).getText().toString().trim());
		} catch (XPatherException e) {
			System.out.println("用户解析失败");
			return null;
		}
		return user;
	}
	
	/**
	 * Analysis the user from the response detail.
	 * @param response
	 * @param user
	 * @return return the user detail with the instance of @see com.calcgpa.core.vo.User
	 */
	protected User analysisUser(String response, User user){
        HtmlCleaner cleaner = new HtmlCleaner();
        TagNode node = cleaner.clean(response);
        Object[] nodes = new Object[0];
		try {
			nodes = node.evaluateXPath("//span[@id='lblXh']");
			user.setId(((TagNode)nodes[0]).getText().toString().trim());
			nodes = node.evaluateXPath("//span[@id='lblXm']");
			user.setName(((TagNode)nodes[0]).getText().toString().trim());
			nodes = node.evaluateXPath("//span[@id='lblBjmc']");
			user.setClasses(((TagNode)nodes[0]).getText().toString().trim());
		} catch (XPatherException e) {
			System.out.println("用户解析失败");
			return null;
		}
		return user;
	}
	
	protected String getViewstate(String response){
        HtmlCleaner cleaner = new HtmlCleaner();
        TagNode node = cleaner.clean(response);
        Object[] nodes = new Object[0];
        String viewstate = "";
		try {
			nodes = node.evaluateXPath("//input[@name='__VIEWSTATE']");
			viewstate = ((TagNode)nodes[0]).getAttributeByName("value");
		} catch (XPatherException e) {
			System.out.println("viewstate解析失败");
			return null;
		}
		return viewstate;
		
	}
	
	/**
	 * Shut down the httpClient.
	 */
	protected void end(){
		httpClient.getConnectionManager().shutdown();
	}
	
	private Double getScoreByGrade(String s){
		if (s.equals("优秀")) return 95.0;
		if (s.equals("良好")) return 85.0;
		if (s.equals("中等")) return 75.0;
		if (s.equals("及格")) return 65.0;
		if (s.equals("不及格")) return 0.0;
		return Double.valueOf(s);
	}

}
